export class MyPromise<P> {
  static async all<T>(promiseList: Promise<T>[]): Promise<T[]> {
    if (!promiseList.length) return Promise.resolve([]);
    let resList: T[] = new Array(promiseList.length);
    let sum = 0;
    return new Promise((resolve, reject) => {
      promiseList.forEach((item, index) => {
        item
          .then((v) => {
            resList[index] = v;
            sum++;
            if (sum === promiseList.length) resolve(resList);
          })
          .catch(reject);
      });
    });
  }
  static async race<T>(promiseList: Promise<T>[]): Promise<T> {
    // 显式处理空数组情况
    if (!promiseList.length) {
      // 返回一个永远pending的promise，与原生行为一致
      return new Promise(() => {});
    }

    return new Promise((resolve, reject) => {
      // 一旦任何一个promise完成，就resolve/reject返回的promise
      promiseList.forEach((item) => {
        // Promise.resolve(item).then(resolve, reject);
        MyPromise.resolve(item).then(resolve, reject);
      });
    });
  }
  static resolve<T>(value: T | Promise<T>): Promise<T> {
    if (value instanceof Promise) {
      return value;
    }
    return new Promise((resolve) => {
      resolve(value);
    });
  }
  static reject<T>(reason: T | Promise<T>): Promise<T> {
    if (reason instanceof Promise) {
      return reason;
    }
    return new Promise((_, reject) => {
      reject(reason);
    });
  }
  static allSettled<T>(
    promiseList: Promise<T>[]
  ): Promise<{ status: "fulfilled" | "rejected"; value?: T; reason?: T }[]> {
    if (!promiseList.length) return Promise.resolve([]);
    let resList: { status: "fulfilled" | "rejected"; value?: T; reason?: T }[] =
      new Array(promiseList.length);
    let sum = 0;
    return new Promise((resolve) => {
      promiseList.forEach((item, index) => {
        item
          .then((v) => {
            resList[index] = { status: "fulfilled", value: v };
            sum++;
            if (sum === promiseList.length) resolve(resList);
          })
          .catch((e) => {
            resList[index] = { status: "rejected", reason: e };
            sum++;
            if (sum === promiseList.length) resolve(resList);
          });
      });
    });
  }
}

class EventBus {
  #eventMap = new Map<string, Array<(...args: any[]) => void>>();
  on(eventName: string, callback: (...args: any[]) => void) {
    if (!this.#eventMap.has(eventName)) {
      this.#eventMap.set(eventName, []);
    }
    this.#eventMap.get(eventName)!.push(callback);
    const index = this.#eventMap.get(eventName)!.length - 1;
    return () => this.off(eventName, index);
  }
  emit(eventName: string, ...args: any[]) {
    if (!this.#eventMap.has(eventName)) return;
    this.#eventMap.get(eventName)!.forEach((callback) => callback(...args));
  }
  off(eventName: string, index?: number) {
    if (!this.#eventMap.has(eventName)) return;
    if (index === undefined) {
      this.#eventMap.delete(eventName);
      return;
    }
    this.#eventMap.get(eventName)!.splice(index, 1);
  }
  once(eventName: string, callback: (...args: any[]) => void) {
    let offFn: (() => void) | undefined;
    const onceCallback = (...args: any[]) => {
      callback(...args);
      // 直接调用off函数移除自己
      if (offFn) offFn();
    };

    offFn = this.on(eventName, onceCallback);
    return offFn;
  }
  clear() {
    this.#eventMap.clear();
  }
  getEventNames() {
    return Array.from(this.#eventMap.keys());
  }
}

export class TaskLimit {
  #runningCount = 0;
  #limit: number = 5;
  #taskList: Array<{
    task: () => Promise<unknown>;
    resolve: (value: unknown) => void;
    reject: (reason?: any) => void;
  }> = [];
  constructor(limit: number) {
    this.#limit = limit;
  }
  run(task: () => Promise<unknown>) {
    return new Promise((resolve, reject) => {
      this.#taskList.push({
        task: task,
        resolve: resolve,
        reject: reject,
      });
      this.execute();
    });
  }
  async execute() {
    if (!this.#taskList.length) return;
    if (this.#runningCount === this.#limit) return;
    const taskObj = this.#taskList.shift()!;
    this.#runningCount++;
    try {
      const res = await taskObj.task();
      taskObj.resolve(res);
    } catch (error) {
      taskObj.reject(error);
    } finally {
      this.#runningCount--;
      this.execute();
    }
  }
  async runBatch(tasks: Array<() => Promise<unknown>>) {
    return await Promise.allSettled(tasks.map((task) => this.run(task)))
  }
}


